//MIT License
//
//Copyright(c) 2020 Goodman Tao
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files(the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions :
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.


#ifndef _LB_2_MULTITHREAD_H__
#define _LB_2_MULTITHREAD_H__

#ifdef _LB_2_MULTITHREAD_API

#else
	
	#ifdef _MSC_VER
		#define _LB_2_MULTITHREAD_API __declspec(dllimport)
	#endif // _MSC_VER
	
	#ifdef __GNUC__
		#define _LB_2_MULTITHREAD_API
	#endif // __GNUC__

	
#endif // !_LB_2_MULTITHREAD_API


#include "../__include/_OO_1_Library.h"

#if defined(__GNUC__)
#include <pthread.h>
#include <sys/time.h>
#endif


/******* Concurrence Return Value ****************************************************************/
typedef enum
{
    ConcurrenceReturnValue_NON      = -1,
    /*
     * The requested operation failed */    
    ConcurrenceReturnValue_ERROR    = 0,
    /*
     * The requested operation succeeded */
    ConcurrenceReturnValue_SUCCESS  = 1,
    /*
     * The time specified in the call was reached without acquiring the requested resource */
    ConcurrenceReturnValue_TIMEDOUT = 2,
    /*
     * The requested operation failed because a tesource requested by a test and return function is already in use */
    ConcurrenceReturnValue_BUSY     = 3,
    /*
     * The requested operation failed because it was unable to allocate memory */
    ConcurrenceReturnValue_NOMEM    = 4
}ConcurrenceReturnValue;

/******* Mutex ****************************************************************/
typedef enum
{
    MutexType_NON = -1,
    MutexType_PLAIN = 0,
    MutexType_TIMED = 1,
    MutexType_RECURSIVE = 2,
    MutexType_PLAIN_RECURSIVE = MutexType_PLAIN | MutexType_RECURSIVE,
    MutexType_TIMED_RECURSIVE = MutexType_TIMED | MutexType_RECURSIVE
}MutexType;

__CLASS Mutex;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
_LB_2_MULTITHREAD_API __CONSTRUCTOR(Mutex);
#ifdef __cplusplus
}
#endif // __cplusplus
__METHODDECLARE(
    void Init(MutexType type, ConcurrenceReturnValue *pRetVal);
    void Lock(ConcurrenceReturnValue *pRetVal);
    void TimedLock(const struct timespec *ts, ConcurrenceReturnValue *pRetVal);
    void TryLock(ConcurrenceReturnValue *pRetVal);
    void Unlock(ConcurrenceReturnValue *pRetVal);
)

/******* Condition Variables ****************************************************************/
__CLASS ConditionVariable;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
_LB_2_MULTITHREAD_API __CONSTRUCTOR(ConditionVariable);
#ifdef __cplusplus
}
#endif // __cplusplus
__METHODDECLARE(
    void Init(ConcurrenceReturnValue * pRetVal);
    void Signal(ConcurrenceReturnValue *pRetVal);
    void Broadcast(ConcurrenceReturnValue *pRetVal);
    void Wait(Mutex *mtx, ConcurrenceReturnValue *pRetVal);
    void TimedWait(Mutex *mtx, const struct timespec *ts, ConcurrenceReturnValue *pRetVal);
)

/******* Thread ****************************************************************/
typedef int(*ThreadStart)(void *pArg);

__CLASS Thread;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
_LB_2_MULTITHREAD_API __CONSTRUCTOR(Thread);
#ifdef __cplusplus
}
#endif // __cplusplus
__METHODDECLARE(
    /*
     * Create a new thread.
     * start: A function pointer to the function that will be executed in the new thread.
     * pArg: An argument to the thread function.
     * pRetVal: NOMEM if no memory could be allocated for the thread requested, or ERROR
     * if the request could not be honored. */
    void Create(ThreadStart start, void *pArg, ConcurrenceReturnValue *pRetVal);
    /*
     * Dispose of any resources allocated to the thread when that thread exits. */
    void Detach(ConcurrenceReturnValue *pRetVal);
    /*
     * Compare two threads.
     * The method determines if two threads are the same.
     * Zero if the two thread identifiers refer to different threads.
     * Otherwise a nonzero value is returned. */
    void Equal(Thread *pTh, ConcurrenceReturnValue *pRetVal);
    /*
     * Wait for a thread to terminate.
     * The method joins the thread with the current thread by blocking until the other 
     * thread has terminated.
     * res: If this pointer is not NULL, the function will store the result code of the
     * thread in the integer pointed to by res. */
    void Join(int *res, ConcurrenceReturnValue *pRetVal);
)

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
__STATICDEFINE(Thread, _LB_2_MULTITHREAD_API)
{
    Thread *(*Current)();
    /*
     * Put the calling thread to sleep.
     * Suspend execution of the calling thread.
     * duration: Interval to sleep for
     * remaining: If non-NULL, this parameter will hold the remaining
     *     time until time_point upon return. This will
     *     typically be zero, but if the thread was woken up
     *     by a signal that is not ignored before duration was
     *     reached @c remaining will hold a positive time.
     * 0 (zero) on successful sleep, -1 if an interrupt occurred,
     *     or a negative value if the operation fails. */
    int(*Sleep)(const struct timespec *duration, struct timespec *remaining);
    void(*Exit)(int retCode);
    void(*Yield)();
};
#ifdef __cplusplus
}
#endif // __cplusplus

/******* Thread local object ******************************************************************************/
#if defined(_MSC_VER)
    #define ThreadLocal __declspec(thread)
#endif
#if defined(__GNUC__)
    #define ThreadLocal __thread
#endif

/******* Thread local storage ******************************************************************************/
typedef void(*ThreadLocalStorageRelease)(void *val);
typedef void *ThreadLocalStorage;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
__STATICDEFINE(ThreadLocalStorage, _LB_2_MULTITHREAD_API)
{
    ConcurrenceReturnValue(*Create)(ThreadLocalStorage *key, ThreadLocalStorageRelease destructor);
    void(*Delete)(ThreadLocalStorage key);
    void *(*Get)(ThreadLocalStorage key);
    ConcurrenceReturnValue(*Set)(ThreadLocalStorage key, void *val);
};
#ifdef __cplusplus
}
#endif // __cplusplus

/********* Once flag *****************************************************************************************/
#if defined(_MSC_VER)
    #include <Windows.h>
    /*
     * type define -> OnceFlag */
    typedef struct { LONG volatile status; CRITICAL_SECTION lock; } OnceFlag;
    /*
     * initial value */
    #define ONCEFLAGINIT {0,}
#endif
#if defined(__GNUC__)
    /*
     * type define -> OnceFlag */
    #define OnceFlag pthread_once_t
     /*
      * initial value */
    #define ONCEFLAGINIT PTHREAD_ONCE_INIT
#endif

#ifdef __cplusplus
    extern "C" {
#endif // __cplusplus
__STATICDEFINE(OnceFlag, _LB_2_MULTITHREAD_API)
{
    void(*CallOnce)(OnceFlag *flag, void(*func)(void));
};
#ifdef __cplusplus
}
#endif // __cplusplus

#endif // !_LB_2_MULTITHREAD_H__

